Introducción

Actualmente, FORM enfrenta la necesidad y la gran oportunidad de optimizar su cadena de producción en función de la demanda de sus diversos productos. Es crucial generar predicciones precisas de la demanda para que FORM pueda aumentar la eficiencia en toda su cadena de producción, reducir costos y mejorar el servicio al cliente. Para lograr esto, se desarrollará un modelo de series temporales utilizando técnicas de modelado como SARIMA, con el fin de predecir las ventas futuras basándose en los datos históricos de ventas de los últimos años.

Justificación del modelo

Se escogió un modelo SARIMA debido a que la naturaleza de los datos permite acoplarse muy bien con modelos de series de tiempo y dicho modelo logra capturar los componentes estacionales de la serie.

Datos utilzados

Se utilizó la base de datos VENTAS_FORM_FJ_2024 proporcionada por la empresa, la cual incluye un registro detallado de sus ventas en el periodo 2021-2023.

Modelado

library(readr)
library(ggplot2)
library(tidyr)
library(viridis)
library(scales) 
library(readxl)
library(RColorBrewer)
library(dplyr)
library(caret)
library(MASS)
library(rpart)
library(rpart.plot)
library(party)
library(gmodels)
library(knitr)
library(readxl)
library(readr)
library(dplyr)
library(cluster)
library(ggplot2)
library(corrplot)
library(tseries)
library(e1071)
library(pROC)
library(ISLR)
library(knitr)
library(gridExtra)
library(car)
library(DataExplorer)
library(tidyr)
library(ggplot2)
library(randomForest)
library(class)
library(caret)
library(cluster)    
library(factoextra) 
library(purrr)
library(imputeTS)
library(xts)
library(zoo)
library(tseries)
library(stats)
library(forecast)
library(astsa)
library(corrplot)
library(wordcloud)
library(tidytext)
library(AER)
library(vars)
library(dynlm)
library(mFilter)
library(TSstudio)
library(tidyverse)
library(sarima)
library(readr)
library(readxl)
library(heatmaply)
library(dplyr)
library(ggplot2)
library(psych)
library(tidyr)
library(readtext)
library(syuzhet)
library(RColorBrewer)
library(tm)
library(caret)
library(MASS)
library(rpart)
library(rpart.plot)
library(party)
library(gmodels)
library(knitr)
library(cluster)    
library(e1071)
library(pROC)
library(ISLR)
library(gridExtra)
library(car)
library(DataExplorer)
library(randomForest)
library(class)
library(factoextra)
library(purrr)
ventas_nv <- read_csv("/Users/gabrielmedina/Desktop/git/git/Case_Study_FORM/databases/form/VENTAS_FORM_B.csv")
## Rows: 37 Columns: 6
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (1): Mes
## dbl (5): Año, Total Carton, Total Retornable, Servicios, Ventas Totales
## 
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
head(ventas_nv)
## # A tibble: 6 × 6
##   Mes       Año `Total Carton` `Total Retornable` Servicios `Ventas Totales`
##   <chr>   <dbl>          <dbl>              <dbl>     <dbl>            <dbl>
## 1 Enero    2021         283978               1137       127           285242
## 2 Febrero  2021         333858               1405         0           335263
## 3 Marzo    2021         274885               5114        58           280057
## 4 Abril    2021         266280               1494         0           267774
## 5 Mayo     2021         179193               4380         4           183577
## 6 Junio    2021         140761               1980         0           142741
na_count <- colSums(is.na(ventas_nv))
na_count
##              Mes              Año     Total Carton Total Retornable 
##                1                1                1                1 
##        Servicios   Ventas Totales 
##                1                1
# Renombra columnas
names(ventas_nv)[names(ventas_nv) == "Ventas Totales"] <- "Ventas_totales"
names(ventas_nv)[names(ventas_nv) == "Total Carton"] <- "Total_carton"
names(ventas_nv)[names(ventas_nv) == "Total Retornable"] <- "Total_retornable"
names(ventas_nv)
## [1] "Mes"              "Año"              "Total_carton"     "Total_retornable"
## [5] "Servicios"        "Ventas_totales"
Sys.setlocale("LC_TIME", "es_ES.UTF-8")
## [1] "es_ES.UTF-8"
ventas_nv <- na.omit(ventas_nv[, c("Año", "Mes", "Ventas_totales", "Total_carton", "Total_retornable", "Servicios")])
ventas_nv$Fecha <- as.Date(paste(ventas_nv$Año, ventas_nv$Mes, "01"), format = "%Y %B %d")
ventas_t <- ts(ventas_nv$Ventas_totales, start = c(as.numeric(format(min(ventas_nv$Fecha), "%Y")), as.numeric(format(min(ventas_nv$Fecha), "%m"))), frequency = 12)
ts_plot(ventas_t)
Carton <- ts(ventas_nv$Total_carton, start = c(year(min(ventas_nv$Fecha)), month(min(ventas_nv$Fecha))), frequency = 12)

ts_plot(Carton)
Retornable <- ts(ventas_nv$Total_retornable, start = c(year(min(ventas_nv$Fecha)), month(min(ventas_nv$Fecha))), frequency = 12)
ts_plot(Retornable)
servicio <- ts(ventas_nv$Servicios, start = c(year(min(ventas_nv$Fecha)), month(min(ventas_nv$Fecha))), frequency = 12)
ts_plot(servicio)
adf.test(ventas_t)
## 
##  Augmented Dickey-Fuller Test
## 
## data:  ventas_t
## Dickey-Fuller = -4.7058, Lag order = 3, p-value = 0.01
## alternative hypothesis: stationary

Con la prueba de ADF podemos observar que la serie de tiempo de las ventas es estacionaria, es decir, no muestra tendencias a lo largo del tiempo y es ideal para modelar un ARIMA que logre capturar los componentes estacionales de la serie de tiempo

# Graficar la ACF y PACF
par(mfrow = c(1, 2))
acf(ventas_t, main = "ACF de Ventas Totales")
pacf(ventas_t, main = "PACF de Ventas Totales")

# Ajustar el modelo ARMA con p=1 y q=1
sarima <- auto.arima(ventas_t, seasonal = TRUE)
summary(sarima)
## Series: ventas_t 
## ARIMA(1,0,0) with non-zero mean 
## 
## Coefficients:
##          ar1       mean
##       0.7659  175677.34
## s.e.  0.1114   26036.11
## 
## sigma^2 = 1.648e+09:  log likelihood = -432.51
## AIC=871.01   AICc=871.76   BIC=875.76
## 
## Training set error measures:
##                    ME    RMSE      MAE       MPE     MAPE      MASE       ACF1
## Training set -3422.67 39453.7 31583.27 -7.366077 20.37777 0.4829533 -0.1033301

El modelo ARMA(1,1) ajustado a la serie de tiempo de ventas muestra que el componente autorregresivo es altamente significativo, indicando que las ventas actuales dependen fuertemente de las ventas pasadas. Sin embargo, el componente de media móvil no es significativo. La significancia del intercepto sugiere un término constante relevante. A pesar de la variabilidad en los residuos, este modelo proporciona una base sólida para capturar las dinámicas de las ventas.

Pruebas de diagnóstico

Modelo Arma

sarima_residuals<-sarima$residuals
Box.test(sarima_residuals,lag=1,type="Ljung-Box")
## 
##  Box-Ljung test
## 
## data:  sarima_residuals
## X-squared = 0.41732, df = 1, p-value = 0.5183

El valor de p obtenido en la prueba de Box-Ljung (0,88) es mayor que el valor de p máximo comúnmente utilizado que es 0,05. Esto significa que no se encontró evidencia significativa de autocorrelación en los residuos, ya que el valor p es mayor que 0,05, lo que respalda la validez del modelo en términos de autocorrelación.

#Testing residuals
suppressWarnings({
sarima$residuals <- na.omit(sarima$residuals)
adf.test(sarima$residuals)
})
## 
##  Augmented Dickey-Fuller Test
## 
## data:  sarima$residuals
## Dickey-Fuller = -5.1649, Lag order = 3, p-value = 0.01
## alternative hypothesis: stationary

El valor de p de 0,01, inferior al umbral de 0,05, indica una fuerte evidencia contra la hipótesis nula de no estacionariedad. Esto significa que es poco probable que los residuos sean no estacionarios.

Predicciones

# Realizar predicciones para los próximos 4 meses
forecast_sarima <- forecast(sarima, h = 7)

# Graficar las predicciones
autoplot(forecast_sarima) +
  ggtitle("Predicciones de Ventas Totales") +
  xlab("Tiempo") +
  ylab("Ventas Totales")

forecast_sarima
##          Point Forecast    Lo 80    Hi 80    Lo 95    Hi 95
## Jan 2024       143252.7 91224.91 195280.5 63683.04 222822.4
## Feb 2024       150844.5 85311.21 216377.8 50619.98 251069.0
## Mar 2024       156658.8 84368.51 228949.1 46100.34 267217.2
## Apr 2024       161111.7 85137.26 237086.2 44918.81 277304.6
## May 2024       164522.1 86467.53 242576.6 45147.96 283896.2
## Jun 2024       167133.9 87884.73 246383.1 45932.74 288335.1
## Jul 2024       169134.3 89192.63 249075.9 46874.10 291394.4

Conclusiones

El modelo SARIMA ajustado a la serie de tiempo de ventas ha sido utilizado para realizar predicciones para los próximos 12 meses. Las predicciones muestran la tendencia esperada de las ventas totales, proporcionando una herramienta valiosa para la planificación y la toma de decisiones en la optimización de la cadena de producción. La significancia del componente autorregresivo sugiere que las ventas pasadas tienen un impacto considerable en las ventas futuras, mientras que el componente de media móvil no resultó ser significativo en este modelo. Las pruebas de diagnóstico respaldan la validez del modelo, indicando que no hay autocorrelación significativa en los residuos y que los residuos son estacionarios. Se sugiere complementar el modelo con más datos históricos de la compañía, así como de variables externas que impactan a las ventas de FORM.